#include "ibac_api.h"

static int child( int index , int req_count , char *node , char *app , char *msg , int msg_len , int pipe_fds[2] )
{
	struct IbacEnv		*p_env = NULL ;
	char			pipe_buf ;
	char			*p_msg = NULL ;
	int			p_msg_len ;
	int			count ;
	
	int			nret = 0 ;
	
	p_env = IBACCreateEnvirment( NULL ) ;
	if( p_env == NULL )
	{
		printf( " CHILD : [%d] IBACCreateEnvirment failed , errno[%d]\n" , index , errno );
		exit(1);
	}
	
	for( count = 0 ; ; count++ )
	{
		nret = read( pipe_fds[0] , & pipe_buf , 1 ) ;
		if( nret == -1 )
		{
			printf( " CHILD : [%d] read failed , errno[%d]\n" , index , errno );
			exit(1);
		}
		
		if( pipe_buf == 'T' )
		{
			p_msg = msg ;
			p_msg_len = msg_len ;
			nret = IBACRequester( p_env , node , app , & p_msg , & p_msg_len , NULL , NULL ) ;
			if( nret )
			{
				printf( " CHILD : [%d] IBACRequester failed[%d] , errno[%d]\n" , index , nret , errno );
				exit(1);
			}
		}
		else if( pipe_buf == 'Q' )
		{
			break;
		}
	}
	
	IBACDestroyEnvirment( p_env );
	
	return 0;
}

static int parent( int proc_count , int req_count , char *node , char *app , int msg_len )
{
	pid_t		*a_pids = NULL ;
	pid_t		pid ;
	int		pipe_fds[ 2 ] ;
	char		*msg = NULL ;
	int		i , j ;
	int		per_count ;
	struct timeval	t1 , t2 , tdiff ;
	double		total_elapse ;
	double		TPS ;
	double		SPT ;
	int		status ;
	
	int		nret = 0 ;
	
	setbuf( stdout , NULL );
	
	a_pids = (pid_t*)malloc( sizeof(pid_t) * proc_count ) ;
	if( a_pids == NULL )
	{
		printf( "malloc failed , errno[%d]\n" , errno );
		return -1;
	}
	memset( a_pids , 0x00 , sizeof(pid_t) * proc_count );
	
	nret = pipe( pipe_fds ) ;
	if( nret == -1 )
	{
		printf( "pipe failed , errno[%d]\n" , errno );
		return -1;
	}
	
	msg = (char*)malloc( msg_len+1 ) ;
	if( msg == NULL )
	{
		printf( "malloc failed , errno[%d]\n" , errno );
		return -1;
	}
	memset( msg , 'X' , msg_len );
	msg[msg_len] = '\0' ;
	
	for( i = 0 ; i < proc_count ; i++ )
	{
		a_pids[i] = fork() ;
		if( a_pids[i] == -1 )
		{
			printf( "PARENT : fork[%d] failed , errno[%d]\n" , i , errno );
			return -1;
		}
		else if( a_pids[i] == 0 )
		{
			printf( " CHILD : [%d] [%d]fork[%d] ok\n" , i , getppid() , getpid() );
			child( i , req_count , node , app , msg , msg_len , pipe_fds );
			exit(0);
		}
		else
		{
			printf( "PARENT : [%d] [%d]fork[%d] ok\n" , i , getpid() , a_pids[i] );
		}
	}
	
	gettimeofday( & t1 , NULL );
	
	per_count = req_count / 10 ;
	for( i = 0 ; i < req_count ; i++ )
	{
		if( (i%per_count) == 0 )
			printf( "PARENT : [%d] requests done\n" , i );
		
		write( pipe_fds[1] , "T" , 1 );
	}
	
	for( i = 0 ; i < req_count ; i++ )
	{
		write( pipe_fds[1] , "Q" , 1 );
	}
	
	for( i = 0 ; i < proc_count ; i++ )
	{
		pid = waitpid( a_pids[i] , & status , 0 ) ;
		if( pid == -1 )
		{
			printf( "PARENT : [%d] waitpid[%d] failed , errno[%d]\n" , i , a_pids[i] , errno );
			for( j = 0 ; j < proc_count ; j++ )
			{
				kill( a_pids[j] , SIGTERM );
			}
			return -1;
		}
		else
		{
			printf( "PARENT : [%d] waitpid[%d] ok , status[%d]\n" , i , a_pids[i] , status );
		}
	}
	
	gettimeofday( & t2 , NULL );
	tdiff.tv_sec = t2.tv_sec - t1.tv_sec ;
	tdiff.tv_usec = t2.tv_usec - t1.tv_usec ;
	if( tdiff.tv_usec < 0 )
	{
		tdiff.tv_sec--;
		tdiff.tv_usec += 1000000 ;
	}
	
	total_elapse = (double)(tdiff.tv_sec) + (double)(tdiff.tv_usec)/1000000 ;
	if( total_elapse == 0.00 )
		TPS = 0.00 ;
	else
		TPS = (double)req_count / total_elapse ;
	if( req_count == 0 )
		SPT = 0.00 ;
	else
		SPT = total_elapse / (double)req_count ;
	printf( "RESULT >>> total_elapse[%lf] TPS[%.2lf] SPT[%lf]\n" , total_elapse , TPS , SPT );
	
	free( msg );
	free( a_pids );
	
	return 0;
}

static void usage()
{
	printf( "USAGE : TESTPSSL (proc_count) (req_count) (node) (app) (msglen)\n" );
	return;
}

int main( int argc , char *argv[] )
{
	int		nret = 0 ;
	
	if( argc == 1 + 5 )
	{
		IBPInitLogEnv( "" , "TESTPSSL" , "file::log/event.log" , LOG_LEVEL_WARN , "file::log/ibp_test_pssl.log" );
		nret = parent( atoi(argv[1]) , atoi(argv[2]) , argv[3] , argv[4] , atoi(argv[5]) ) ;
		IBPCleanLogEnv();
		return -nret;
	}
	else
	{
		usage();
		exit(7);
	}
}

